package main

import (
    "fmt"
    "reflect"
)

// --- 反射的基本概念 ---
// 反射是程序在运行时检查其自身结构的能力，特别是类型。
// 反射在 Go 中由 reflect 包提供。
// 反射的两大核心类型是 Type 和 Value。
// reflect.TypeOf() 返回值的类型 (reflect.Type)。
// reflect.ValueOf() 返回值的值 (reflect.Value)。

type Person struct {
    Name string `json:"name"` // 标签 是反射中一个重要的应用
    Age  int    `json:"age"`
}

func (p Person) Greet() {
    fmt.Printf("你好，我是 %s，今年 %d 岁。\n", p.Name, p.Age)
}

func main() {
    // --- Type 和 Value ---
    fmt.Println("--- Type 和 Value ---")
    var x float64 = 3.4
    fmt.Printf("变量 x 的类型是: %T\n", x) // 普通的类型打印
    t := reflect.TypeOf(x)                // 使用反射获取类型
    fmt.Printf("reflect.TypeOf(x) 的结果是: %v\n", t)
    v := reflect.ValueOf(x) // 使用反射获取值
    fmt.Printf("reflect.ValueOf(x) 的结果是: %v\n", v)

    // 从 reflect.Value 获取 reflect.Type
    fmt.Printf("从 v.Type() 获取的类型是: %v\n", v.Type())
    fmt.Println()

    // --- Kind ---
    // Kind 是一个更基础的类型分类，例如，一个变量可以是 struct Kind，但其具体类型可能是 Person。
    fmt.Println("--- Kind ---")
    fmt.Printf("t 的 Kind 是: %v\n", t.Kind()) // float64 的 Kind 是 float64
    p := Person{"张三", 30}
    tp := reflect.TypeOf(p)
    fmt.Printf("Person 类型的 Kind 是: %v\n", tp.Kind()) // struct Kind
    fmt.Println()

    // --- 通过反射修改值 ---
    // 反射可以用来修改变量的值，但前提是传入的是变量的指针。
    fmt.Println("--- 通过反射修改值 ---")
    var y float64 = 3.4
    fmt.Println("修改前 y 的值:", y)
    // 必须传入指针，否则无法修改原始变量
    vp := reflect.ValueOf(&y)
    // 使用 Elem() 获取指针指向的值
    ve := vp.Elem()
    // 使用 CanSet() 检查是否可以设置
    if ve.CanSet() {
        // 使用 SetFloat() 设置新值
        ve.SetFloat(7.1)
        fmt.Println("修改后 y 的值:", y)
    } else {
        fmt.Println("无法设置值")
    }
    fmt.Println()

    // --- 反射与结构体 ---
    fmt.Println("--- 反射与结构体 ---")
    s := Person{"李四", 25}
    vs := reflect.ValueOf(s)
    ts := vs.Type()

    // 遍历结构体的字段
    for i := 0; i < ts.NumField(); i++ {
        field := ts.Field(i)
        value := vs.Field(i)
        fmt.Printf("字段名: %s, 字段类型: %v, 字段值: %v, 标签: %s\n", field.Name, field.Type, value, field.Tag.Get("json"))
    }
    fmt.Println()

    // --- 反射与方法 ---
    fmt.Println("--- 反射与方法 ---")
    // 获取方法
    greetMethod := vs.MethodByName("Greet")
    if greetMethod.IsValid() {
        fmt.Println("找到了 Greet 方法")
        // 调用方法 (没有参数)
        greetMethod.Call(nil)
    } else {
        fmt.Println("未找到 Greet 方法")
    }
    fmt.Println()

    // --- 反射的动态性 ---
    fmt.Println("--- 反射的动态性 ---")
    // 处理未知类型的切片
    processSlice([]int{1, 2, 3})
    processSlice([]string{"a", "b", "c"})
    processSlice("我不是一个切片") // 传入错误类型
}

// processSlice 函数可以处理任何类型的切片
func processSlice(data interface{}) {
    v := reflect.ValueOf(data)
    if v.Kind() != reflect.Slice {
        fmt.Printf("输入 %v 不是一个切片\n", data)
        return
    }

    fmt.Printf("处理切片 %v (类型: %T):\n", data, data)
    for i := 0; i < v.Len(); i++ {
        element := v.Index(i)
        fmt.Printf("  索引 %d: 值为 %v (类型: %v)\n", i, element.Interface(), element.Kind())
    }
    fmt.Println()
}